/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package serwer.prezentacja;


import sun.security.rsa.RSAPublicKeyImpl;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import com.esotericsoftware.kryonet.Server;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import network.szyfrowanie.Klucze;
import sun.security.rsa.RSAKeyFactory;
import sun.security.rsa.RSAPrivateCrtKeyImpl;
//import sun.security.rsa.RSAPrivateKeyImpl;
import network.szyfrowanie.SzyfrowanieRSA;
import serwer.dane.DaneSesji;
import serwer.dane.Sesja;


public class UstalanieKlucza extends SzyfrowanieRSA {
   // PublicKey pub;
    PrivateKey priv;
    HashMap zbior;
    HashMap zbiorKluczy;
    Server server;
    
    public UstalanieKlucza(HashMap hm) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException{
     //   final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
     //   final KeyPair keyPair = generator.generateKeyPair();
        zbiorKluczy=hm;
   //     pub = keyPair.getPublic(); //klucz publiczny
    //    priv = keyPair.getPrivate(); //klucz prywatny
        UstawKlucz();
     //   RSAPrivateCrtKeyImpl a=(RSAPrivateCrtKeyImpl)priv;
     //   System.out.println(a.getModulus());
        zbior=new HashMap();
        
    }
    
    private byte[] generujPodpis(PublicKey p) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(p.getEncoded());
        byte[] hashed = md.digest();
        return odszyfruj(hashed,priv,1);
        
    }
   
    
    private void UstawKlucz() throws NoSuchAlgorithmException, InvalidKeySpecException{
            byte[] b=new byte[635];
            File file = new File("private");
            FileInputStream fis = null;

            try {
                fis = new FileInputStream(file);

                 int content;
                 int i=0;
                int read = fis.read(b);

            } catch (IOException e) {
            } finally {
                try {
                    if (fis != null)
                        fis.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(b);
            KeyFactory rsaFact = KeyFactory.getInstance("RSA");
            priv = (RSAPrivateKey) rsaFact.generatePrivate(spec);
}
    
    public void sluchaj(int port) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException{
            server = new Server();
	  
	    try{
	    server.bind(port);
	    }catch(IOException a){
	    	System.out.println("Wyjątek:" + a);
	    }
        Kryo kryo = server.getKryo();//Rejestrujemy klasy do serwera
	kryo.register(Klucze.class);
        kryo.register(byte[].class);
        kryo.register(String.class);
	server.addListener(new Listener() {
                @Override
	        public void received (Connection connection, Object object) {
                       //     System.out.println("received");
                    if (object instanceof byte[]) {
                        try {
                            byte[] b=(byte[])object;
                            PublicKey request = new RSAPublicKeyImpl(b);
                            KeyGenerator kGen = KeyGenerator.getInstance("AES"); //Tworzenie klucza poczatek
                            kGen.init(128);
                            SecretKey sKey = kGen.generateKey();
                            byte[] rawKey = sKey.getEncoded();// Tworzenie klucza koniec
                            final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
                            final KeyPair keyPair = generator.generateKeyPair();
                            PublicKey pub = keyPair.getPublic(); //klucz publiczny
                            PrivateKey priv = keyPair.getPrivate(); //klucz prywatny
                            byte[] zasz=szyfruj(rawKey,request);
                            String ksesji=generujSesje();
                            zbior.put(ksesji,new DaneSesji(rawKey,priv));
                            connection.sendTCP(new Klucze(pub,zasz,ksesji,generujPodpis(pub)));
                        } catch (                NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex) {
                            Logger.getLogger(UstalanieKlucza.class.getName()).log(Level.SEVERE, null, ex);
                        }
                        
                   }
	           if (object instanceof Klucze) {
	        	   Klucze request = (Klucze)object;
                           String spr=request.getSesja();
                           if(zbior.containsKey(spr)){
                               try {
                                   byte[] k;
                                   DaneSesji sd=(DaneSesji)zbior.get(spr);
                                   k = request.getKlucz();
                                   PrivateKey priv=sd.getPriv();
                                   k=odszyfruj(k,priv);
                                   byte[] p=sd.getKlucz();
                                   byte[] nw=new byte[p.length];
                                   for(int i=0;i<p.length;i++){
                                       nw[i]=(byte) (p[i]^k[i]);
                              //         System.out.println(i+": "+nw[i]);//Do wyrzucenia
                                   }
                                   zbiorKluczy.put(spr,new Sesja(nw));
                                   zbior.remove(spr);
                               } catch (                       NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex) {
                                   Logger.getLogger(UstalanieKlucza.class.getName()).log(Level.SEVERE, null, ex);
                               }
                           }
	           }
	        }
                @Override
                public void connected(Connection con){
                    System.out.println("Połączono");
                }
                
                
            @Override
            public void disconnected(Connection connection) {
                  System.out.println("Rozłączono");
            }

                private String generujSesje() {
                     String sesja = "";
                     for ( int i = 0; i < 40;i++ )
                         sesja += (char) (byte)( Math.random() * 256 );
           //          System.out.println(sesja);
                     return sesja; 
                }
	     });
        
	    server.start();
    }
    
    public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException{
        HashMap hm=new HashMap();
        UstalanieKlucza o=new UstalanieKlucza(hm);
        o.sluchaj(54555);
    }
}